package com.sinosoft.hydra.um.services;

import cn.com.sinux.spring.commons.SystemConfig;
import cn.com.sinux.spring.exception.BusinessException;
import cn.com.sinux.spring.utils.ConvertUtils;
import cn.com.sinux.spring.utils.DateUtils;
import cn.com.sinux.spring.utils.QueryHelper;
import cn.com.sinux.spring.utils.SpecificationHelper;
import com.sinosoft.hydra.um.LoginUser;
import com.sinosoft.hydra.um.condition.SearchAttendanceCondition;
import com.sinosoft.hydra.um.constant.BaseConstant;
import com.sinosoft.hydra.um.domain.model.DirectoryType;
import com.sinosoft.hydra.um.domain.permission.*;
import com.sinosoft.hydra.um.helper.AuthContextHelper;
import com.sinosoft.hydra.um.repositories.TApproRecordDAO;
import com.sinosoft.hydra.um.repositories.TAttendanceDAO;
import org.apache.commons.lang.StringUtils;
import org.hibernate.jpa.criteria.CriteriaBuilderImpl;
import org.hibernate.jpa.criteria.OrderImpl;
import org.hibernate.jpa.criteria.expression.function.CurrentTimeFunction;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.*;
import javax.persistence.metamodel.EntityType;
import java.util.*;

/**
 * Created by lcb on 2016/8/31.
 */
@Service
public class AttendanceService {

    @Autowired
    private TAttendanceDAO attendanceDAO;
    @Autowired
    private TApproRecordDAO approRecordDAO;
    @Autowired
    private DirectoryService directoryService;
    @Autowired
    private SysResourceService sysResourceService;

    @Transactional
    public TAttendance addAttendance(final TAttendance attendance) {
        //判断如果是需要审批的则加入审批要求
        if (attendance.getReason() == null || StringUtils.isBlank(attendance.getReason().getId())) {
            throw new BusinessException("必须选择一个考勤事由！");
        }
        TDirectory directory = directoryService.getOne(attendance.getReason().getId());
        attendance.setStatus("attendance".equals(directory.getDirConfig()) ? TAttendance.WAIT : TAttendance.PASS);
        //保证同一个人的去向唯一
        List<TAttendance> list = attendanceDAO.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TAttendance>() {

            public void fillParam(Root<TAttendance> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("applyUser").get("id"), attendance.getApplyUser().getId()));
                list.add(cb.notEqual(root.get("status"), TAttendance.REFUSE));
            }
        }));
        for (TAttendance tAttendance : list) {
            if (tAttendance.getEndTime() == null) {
                throw new BusinessException("该人员还有未完成的考勤信息！");
            }
        }
        //普通用户一周以前的不让补填
        if (attendance.getBeginTime().compareTo(DateUtils.addWeeks(DateUtils.getStartOfDay(new Date()), -1)) < 0 &&
                sysResourceService.hasPermission("attendance:data:add:prev")) {
            throw new BusinessException("开始时间不能是一周以前！");
        }
        attendance.setCreateTime(new Date());
        attendance.setCreateUser(AuthContextHelper.getLoginUser());
        if (attendance.getApplyUser().getId().equals(attendance.getCreateUser().getId())) {
            attendance.setIsReplace(0);
        } else {
            attendance.setIsReplace(1);
        }
        return attendanceDAO.save(attendance);
    }

    @Transactional
    public List<TApproRecord> approRecords() {
        //判断如果是需要审批的则加入审批要求
        return approRecordDAO.findAll();
    }

    @Transactional
    public TAttendance updateAttendance(TAttendance attendance) {
        TAttendance tAttendance = attendanceDAO.findOne(attendance.getId());
        tAttendance.setCreateTime(attendance.getCreateTime());
        tAttendance.setReason(attendance.getReason());
        tAttendance.setRemark(attendance.getRemark());
        tAttendance.setBeginTime(attendance.getBeginTime());
        tAttendance.setEndTime(attendance.getEndTime());
        tAttendance.setProjectCode(attendance.getProjectCode());
        tAttendance.setApm(attendance.getApm());
        if (TAttendance.REFUSE.equals(tAttendance.getStatus())) {
            tAttendance.setStatus(TAttendance.WAIT);
        }
        if (StringUtils.isBlank(attendance.getDays())) {
            tAttendance.setDays(null);
            if (attendance.getEndTime() == null) {
                tAttendance.setEndTime(null);
            } else {
                isOneDay(tAttendance.getBeginTime(), attendance.getEndTime());
                tAttendance.setEndTime(attendance.getEndTime());
            }
        } else {
            tAttendance.setDays(attendance.getDays());
            tAttendance.setEndTime(countEndTime(tAttendance));
        }
        return attendanceDAO.save(tAttendance);
    }

    public List<TApproRecord> getRecords(final TAttendance attendance) {
        return approRecordDAO.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TApproRecord>() {
            @Override
            public void fillParam(Root<TApproRecord> root, CriteriaBuilder cb, List<Predicate> list) {
                cb.createQuery().orderBy(new OrderImpl(root.get("approDate"), false));
                list.add(cb.equal(root.get("tAttendance"), attendance));
            }
        }));
    }

    @Transactional
    public TAttendance addEndTime(TAttendance attendance) {
        TAttendance tAttendance = attendanceDAO.findOne(attendance.getId());
        if (StringUtils.isBlank(attendance.getDays())) {
            if (attendance.getEndTime() == null) {
                tAttendance.setDays(null);
                tAttendance.setEndTime(null);
            } else {
                isOneDay(tAttendance.getBeginTime(), attendance.getEndTime());
                tAttendance.setEndTime(attendance.getEndTime());
            }
        } else {
            tAttendance.setDays(attendance.getDays());
            tAttendance.setEndTime(countEndTime(tAttendance));
        }
        return attendanceDAO.save(tAttendance);
    }

    public void isOneDay(Date begin, Date end) {
        if (!DateUtils.formatDate(begin, "yyyyMMdd").equals(DateUtils.formatDate(end, "yyyyMMdd"))) {
            throw new BusinessException("结束时间不能跨天！");
        }
    }

//    零星世家 秘書、組長、zhuren
//    其他世家和換休 主人皮

//            登陸頁面
//            分配權限

    /**
     * 获取待考勤的记录
     *
     * @return
     */
    public Page<TAttendance> findWaitApproAttendances(final SearchAttendanceCondition condition, Pageable pageable) {
        LoginUser loginUser = AuthContextHelper.getLoginUser();
        final List<SysOrganization> organizations = loginUser.getSysOrganizations();
        //普通用户一周以前的不让补填
        if (!sysResourceService.hasPermission("attendance:data:approList")) {
            throw new BusinessException("其他角色不具备查看待审批记录的权限！");
        }
        Specification<TAttendance> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TAttendance>() {
            public void fillParam(Root<TAttendance> root, CriteriaBuilder cb, List<Predicate> list) {
                if (condition.getReason() != null && StringUtils.isNotBlank(condition.getReason().getId())) {
                    list.add(cb.equal(root.get("reason").get("id").as(String.class), condition.getReason().getId()));
                }
                if (condition.getApplyUser() != null && StringUtils.isNotBlank(condition.getApplyUser().getId())) {
                    list.add(cb.equal(root.get("applyUser").get("id").as(String.class), condition.getApplyUser().getId()));
                }
                if (StringUtils.isNotBlank(condition.getRemark())) {
                    list.add(cb.like(root.get("remark").as(String.class), "%" + condition.getRemark() + "%"));
                }
                list.add(cb.equal(root.get("status"), TAttendance.WAIT));
                if (sysResourceService.hasPermission("attendance:data:appro:team")) {
                    CriteriaQuery criteriaQuery = cb.createQuery();
                    Subquery<SysUserMember> sysOrganizationUserSubquery = criteriaQuery.subquery(SysUserMember.class);
                    Root<SysOrganizationUser> sysOrganizationUserRoot = sysOrganizationUserSubquery.from(SysOrganizationUser.class);
                    sysOrganizationUserSubquery.select(sysOrganizationUserRoot.<SysUserMember>get("sysUserMember"));
                    CriteriaBuilder.In<SysOrganization> in = cb.in(sysOrganizationUserRoot.get("sysOrganization").as(SysOrganization.class));
                    for (SysOrganization sysOrganization : organizations) {
                        in.value(sysOrganization);
                    }
                    sysOrganizationUserSubquery.where(in);
                    CriteriaBuilder.In<SysUserMember> in2 = cb.in(root.<SysUserMember>get("applyUser"));
                    list.add(in2.value(sysOrganizationUserSubquery));
                    List<TDirectory> directories = directoryService.findDirectories(DirectoryType.valueOf("DIRECTORY_REASON_TYPE"));
                    List<TDirectory> inner = new ArrayList<TDirectory>();
                    for (TDirectory directory : directories) {
                        if ("team.attendance".equals(directory.getDirConfig1())) {
                            inner.add(directory);
                        }
                    }
                    if (!inner.isEmpty()) {
                        CriteriaBuilder.In<TDirectory> in3 = cb.in(root.<TDirectory>get("reason"));
                        for (TDirectory directory : inner) {
                            in3.value(directory);
                        }
                        list.add(in3);
                    }
                }
            }
        });
        return attendanceDAO.findAll(specification, pageable);
    }

    private void updateRecords(final String attenceId) {
        List<TApproRecord> list = approRecordDAO.findAll(SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TApproRecord>() {

            public void fillParam(Root<TApproRecord> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.equal(root.get("tAttendance").get("id"), attenceId));
            }
        }));
        for (TApproRecord approRecord : list) {
            approRecord.setIsNew(BaseConstant.STRING_FALSE);
            approRecordDAO.save(approRecord);
        }
    }

    /**
     * 批量审批考勤
     *
     * @param sysUserMember
     * @param attendances
     */
    @Transactional
    public void approvalAttendances(SysUserMember sysUserMember,
                                    List<TApproRecord> attendances) {
        for (TApproRecord approRecord : attendances) {
            TAttendance db = getOne(approRecord.gettAttendance().getId());
            if (db != null
                    && TAttendance.WAIT.equals(db.getStatus())
                    && StringUtils.isNotBlank(approRecord.getApproStatus())) {
                updateRecords(db.getId());
                approRecord.setApproDate(new Date());
                approRecord.setIsNew(BaseConstant.STRING_TRUE);
                approRecord.setSysUserMember(sysUserMember);
                approRecord.settAttendance(db);
                approRecordDAO.save(approRecord);
                db.setStatus(approRecord.getApproStatus());
                attendanceDAO.save(db);
            }
        }
    }

    public Date countEndTime(TAttendance attendance) {
        Date begin = attendance.getBeginTime();
        String apm = attendance.getApm();
        String days = attendance.getDays();
        String decimalStr = days.substring(days.lastIndexOf(".") + 1);
        String intStr = days.substring(0, days.lastIndexOf("."));
        if (!Arrays.asList("5", "0").contains(decimalStr)) {
            throw new BusinessException("考勤天数只能为0.5的整倍数！");
        }
        if ("0".equals(decimalStr) && "am".equals(apm)) {
            return DateUtils.addDays(DateUtils.setHours(begin, 18), Integer.valueOf(intStr) - 1);
        } else if ("0".equals(decimalStr) && "pm".equals(apm)) {
            return DateUtils.addDays(DateUtils.setHours(begin, 12), Integer.valueOf(intStr));
        } else if ("5".equals(decimalStr) && "am".equals(apm)) {
            return DateUtils.addDays(DateUtils.setHours(begin, 12), Integer.valueOf(intStr));
        } else {
            return DateUtils.addDays(DateUtils.setHours(begin, 18), Integer.valueOf(intStr));
        }
    }

    public Page<TAttendance> findSelfList(final SearchAttendanceCondition condition, Pageable pageable) {
        if (condition == null) {
            return attendanceDAO.findAll(pageable);
        }
        Specification<TAttendance> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TAttendance>() {
            public void fillParam(Root<TAttendance> root, CriteriaBuilder cb, List<Predicate> list) {
                list.add(cb.or(
                        cb.equal(root.get("applyUser").get("id").as(String.class), AuthContextHelper.getLoginUser().getId()),
                        cb.equal(root.get("createUser").get("id").as(String.class), AuthContextHelper.getLoginUser().getId())
                ));
                if (condition.getReason() != null && StringUtils.isNotBlank(condition.getReason().getId())) {
                    list.add(cb.equal(root.get("reason").get("id").as(String.class), condition.getReason().getId()));
                }
                if (condition.getApplyUser() != null && StringUtils.isNotBlank(condition.getApplyUser().getId())) {
                    list.add(cb.equal(root.get("applyUser").get("id").as(String.class), condition.getApplyUser().getId()));
                }
                if (StringUtils.isNotBlank(condition.getRemark())) {
                    list.add(cb.like(root.get("remark").as(String.class), "%" + condition.getRemark() + "%"));
                }
            }
        });
        return attendanceDAO.findAll(specification, pageable);
    }

    public Page<TAttendance> findAll(final SearchAttendanceCondition condition, Pageable pageable) {
        if (condition == null) {
            return attendanceDAO.findAll(pageable);
        }
        Specification<TAttendance> specification = SpecificationHelper.buildSpecification(new SpecificationHelper.SpecificationBuilder<TAttendance>() {

            public void fillParam(Root<TAttendance> root, CriteriaBuilder cb, List<Predicate> list) {
                if (condition.isHome()) {
                    list.add(cb.and(
                            cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), new Date()),
                            cb.or(
                                    cb.greaterThanOrEqualTo(root.get("endTime").as(Date.class), new Date()),
                                    cb.isNull(root.get("endTime"))
                            )
                    ));
                }
                if (condition.getReason() != null && StringUtils.isNotBlank(condition.getReason().getId())) {
                    list.add(cb.equal(root.get("reason").get("id"), condition.getReason().getId()));
                }
                if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isBlank(condition.getMonth())) {
                    GregorianCalendar gc = new GregorianCalendar();
                    gc.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
                    list.add(cb.or(
                            cb.between(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfYear(gc.getTime()), getEndDayOfYear(gc.getTime())),
                            cb.between(root.get("endTime").as(Date.class), DateUtils.getStartDayOfYear(gc.getTime()), getEndDayOfYear(gc.getTime())),
                            cb.and(
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfYear(gc.getTime())),
                                    cb.greaterThanOrEqualTo(root.get("endTime").as(Date.class), getEndDayOfYear(gc.getTime()))
                            ),
                            cb.and(
                                    cb.isNull(root.get("endTime")),
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), getEndDayOfYear(gc.getTime())),
                                    cb.greaterThanOrEqualTo(new CurrentTimeFunction((CriteriaBuilderImpl) cb), DateUtils.getStartDayOfYear(gc.getTime()))
                            )
                    ));
                }
                if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isNotBlank(condition.getMonth())) {
                    GregorianCalendar gc = new GregorianCalendar();
                    gc.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
                    gc.set(Calendar.MONTH, Integer.parseInt(condition.getMonth()) - 1);
                    gc.set(Calendar.DAY_OF_MONTH, 7);
                    list.add(cb.or(
                            cb.between(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfMonth(gc.getTime()), getEndDayOfMonth(gc.getTime())),
                            cb.between(root.get("endTime").as(Date.class), DateUtils.getStartDayOfMonth(gc.getTime()), getEndDayOfMonth(gc.getTime())),
                            cb.and(
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfMonth(gc.getTime())),
                                    cb.greaterThanOrEqualTo(root.get("endTime").as(Date.class), getEndDayOfMonth(gc.getTime()))
                            ),
                            cb.and(
                                    cb.isNull(root.get("endTime")),
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), getEndDayOfMonth(gc.getTime())),
                                    cb.greaterThanOrEqualTo(new CurrentTimeFunction((CriteriaBuilderImpl) cb), DateUtils.getStartDayOfMonth(gc.getTime()))
                            )
                    ));
                }
                if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isNotBlank(condition.getSeason())) {
                    GregorianCalendar gc1 = new GregorianCalendar();
                    gc1.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
                    gc1.set(Calendar.DAY_OF_MONTH, 7);
                    GregorianCalendar gc2 = new GregorianCalendar();
                    gc2.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
                    gc2.set(Calendar.DAY_OF_MONTH, 7);
                    if ("1".equals(condition.getSeason())) {
                        gc1.set(Calendar.MONTH, 1 - 1);
                        gc2.set(Calendar.MONTH, 3 - 1);
                    } else if ("2".equals(condition.getSeason())) {
                        gc1.set(Calendar.MONTH, 4 - 1);
                        gc2.set(Calendar.MONTH, 6 - 1);
                    } else if ("3".equals(condition.getSeason())) {
                        gc1.set(Calendar.MONTH, 7 - 1);
                        gc2.set(Calendar.MONTH, 9 - 1);
                    } else {
                        gc1.set(Calendar.MONTH, 10 - 1);
                        gc2.set(Calendar.MONTH, 12 - 1);
                    }
                    list.add(cb.or(
                            cb.between(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfMonth(gc1.getTime()), getEndDayOfMonth(gc2.getTime())),
                            cb.between(root.get("endTime").as(Date.class), DateUtils.getStartDayOfMonth(gc1.getTime()), getEndDayOfMonth(gc2.getTime())),
                            cb.and(
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), DateUtils.getStartDayOfMonth(gc1.getTime())),
                                    cb.greaterThanOrEqualTo(root.get("endTime").as(Date.class), getEndDayOfMonth(gc2.getTime()))
                            ),
                            cb.and(
                                    cb.isNull(root.get("endTime")),
                                    cb.lessThanOrEqualTo(root.get("beginTime").as(Date.class), getEndDayOfMonth(gc2.getTime())),
                                    cb.greaterThanOrEqualTo(new CurrentTimeFunction((CriteriaBuilderImpl) cb), DateUtils.getStartDayOfMonth(gc1.getTime()))
                            )
                    ));
                }
                if (StringUtils.isNotBlank(condition.getOrgId())) {
                    Join<TAttendance, SysUserMember> applyUser = root.join(root.getModel().getSingularAttribute("applyUser", SysUserMember.class), JoinType.LEFT);
                    ListJoin<SysUserMember, SysOrganizationUser> orgUsers = applyUser.join(((EntityType<SysUserMember>) applyUser.getModel()).getList("sysOrganizationUsers", SysOrganizationUser.class), JoinType.LEFT);
                    list.add(cb.equal(orgUsers.get("sysOrganization").get("id").as(String.class), condition.getOrgId()));
                }
                if (StringUtils.isNotBlank(condition.getUserId())) {
                    list.add(cb.equal(root.get("applyUser").get("id").as(String.class), condition.getUserId()));
                }
            }
        });
        return attendanceDAO.findAll(specification, pageable);
    }

    public List<TAttendance> delAttendances(List<String> ids) {
        List<TAttendance> attendances = attendanceDAO.findAll(ids);
        attendanceDAO.delete(attendances);
        return attendances;
    }

    public TAttendance getOne(String id) {
        return StringUtils.isBlank(id) ? null : attendanceDAO.findOne(id);
    }

    public double countHours(List<TAttendance> attendances) {
        if (attendances.size() == 0) {
            return 0;
        }
        long ms = 0;
        for (TAttendance attendance : attendances) {
            if (attendance.getEndTime() == null) {
                continue;
            }
            long reduce = attendance.getEndTime().getTime() - attendance.getBeginTime().getTime();
            boolean isOneDay = DateUtils.formatDate(attendance.getBeginTime(), "yyyyMMdd")
                    .equals(DateUtils.formatDate(attendance.getEndTime(), "yyyyMMdd"));
            if (!isOneDay || reduce <= 0) {
                throw new BusinessException("数据异常");
            }
            ms += reduce;
        }
        return ms / (60 * 60 * 1000);
    }

    public double countDays(List<TAttendance> attendances, SearchAttendanceCondition condition) {
        if (attendances.size() == 0) {
            return 0;
        }
        double countDays = 0;
        for (TAttendance attendance : attendances) {
            if (attendance.getEndTime() == null) {
                Date now = new Date();
                if (now.compareTo(DateUtils.getStartOfDay(attendance.getBeginTime())) >= 0) {
                    attendance.setEndTime(DateUtils.setHours(DateUtils.getStartOfDay(now), 18));
                } else {
                    continue;
                }
            }
            correctTime(attendance, condition);
            countDays += daysBetween(attendance.getBeginTime(), attendance.getEndTime());
        }
        return countDays;
    }

    public double daysBetween(Date begin, Date end) {
        String beginHour = DateUtils.formatDate(begin, "H");
        String endHour = DateUtils.formatDate(end, "H");
        if (begin == null || end == null || end.getTime() - begin.getTime() <= 0 ||
                !Arrays.asList("8", "14").contains(beginHour) ||
                !Arrays.asList("12", "18").contains(endHour)) {
            throw new BusinessException("数据异常");
        }
//        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
//        try {
//            begin = sdf.parse(sdf.format(begin));
//            end = sdf.parse(sdf.format(end));
//        } catch (ParseException e) {
//            throw new BusinessException("日期格式化转换错误");
//        }
//        double reduce = (double)(end.getTime()-begin.getTime())/(24*60*60*1000);
        double reduce = (end.getTime() - begin.getTime()) / (24 * 60 * 60 * 1000);
        if (Integer.valueOf(beginHour) > Integer.valueOf(endHour)) {
            reduce++;
        }
        if ("8".equals(beginHour) && "18".equals(endHour)) {
            return reduce + 1;
        } else if ("14".equals(beginHour) && "12".equals(endHour)) {
            return reduce;
        } else {
            return reduce + 0.5;
        }
    }

    public void correctTime(TAttendance attendance, SearchAttendanceCondition condition) {
//        if (attendance.getEndTime() == null){
//            attendance.setEndTime(new Date());
//        }
        if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isBlank(condition.getMonth())) {
            GregorianCalendar gc = new GregorianCalendar();
            gc.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
            if (attendance.getBeginTime().getTime() < DateUtils.getStartDayOfYear(gc.getTime()).getTime()) {
                attendance.setBeginTime(DateUtils.setHours(DateUtils.getStartDayOfYear(gc.getTime()), 8));
            }
            if (attendance.getEndTime().getTime() > getEndDayOfYear(gc.getTime()).getTime()) {
                attendance.setEndTime(DateUtils.setHours(getEndDayOfYear(gc.getTime()), 18));
            }
        }
        if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isNotBlank(condition.getMonth())) {
            GregorianCalendar gc = new GregorianCalendar();
            gc.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
            gc.set(Calendar.MONTH, Integer.parseInt(condition.getMonth()) - 1);
            gc.set(Calendar.DAY_OF_MONTH, 7);
            if (attendance.getBeginTime().getTime() < DateUtils.getStartDayOfMonth(gc.getTime()).getTime()) {
                attendance.setBeginTime(DateUtils.setHours(DateUtils.getStartDayOfMonth(gc.getTime()), 8));
            }
            if (attendance.getEndTime().getTime() > getEndDayOfMonth(gc.getTime()).getTime()) {
                attendance.setEndTime(DateUtils.setHours(getEndDayOfMonth(gc.getTime()), 18));
            }
        }
        if (StringUtils.isNotBlank(condition.getYear()) && StringUtils.isNotBlank(condition.getSeason())) {
            GregorianCalendar gc1 = new GregorianCalendar();
            gc1.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
            gc1.set(Calendar.DAY_OF_MONTH, 7);
            GregorianCalendar gc2 = new GregorianCalendar();
            gc2.set(Calendar.YEAR, Integer.parseInt(condition.getYear()));
            gc2.set(Calendar.DAY_OF_MONTH, 7);
            if ("1".equals(condition.getSeason())) {
                gc1.set(Calendar.MONTH, 1 - 1);
                gc2.set(Calendar.MONTH, 3 - 1);
            } else if ("2".equals(condition.getSeason())) {
                gc1.set(Calendar.MONTH, 4 - 1);
                gc2.set(Calendar.MONTH, 6 - 1);
            } else if ("3".equals(condition.getSeason())) {
                gc1.set(Calendar.MONTH, 7 - 1);
                gc2.set(Calendar.MONTH, 9 - 1);
            } else {
                gc1.set(Calendar.MONTH, 10 - 1);
                gc2.set(Calendar.MONTH, 12 - 1);
            }
            if (attendance.getBeginTime().getTime() < DateUtils.getStartDayOfMonth(gc1.getTime()).getTime()) {
                attendance.setBeginTime(DateUtils.setHours(DateUtils.getStartDayOfMonth(gc1.getTime()), 8));
            }
            if (attendance.getEndTime().getTime() > getEndDayOfMonth(gc2.getTime()).getTime()) {
                attendance.setEndTime(DateUtils.setHours(getEndDayOfMonth(gc2.getTime()), 18));
            }
        }
    }

    public String getTimeRange(List<TAttendance> attendances, SearchAttendanceCondition condition) {
        List<TAttendance> list = getStandardTime(attendances, condition);
        List<TAttendance> list1 = mergeDate(list);
        List<String> times = new ArrayList<String>();
        for (TAttendance attendance : list1) {
            String beginDay = DateUtils.formatDate(attendance.getBeginTime(), "M月d日");
            String endDay = DateUtils.formatDate(attendance.getEndTime(), "M月d日");
            String beginHour = DateUtils.formatDate(attendance.getBeginTime(), "H");
            String endHour = DateUtils.formatDate(attendance.getEndTime(), "H");
            if (beginDay.equals(endDay)) {
                if ("0".equals(beginHour) && "12".equals(endHour)) {
                    times.add(beginDay + "上午");
                } else if ("12".equals(beginHour) && "23".equals(endHour)) {
                    times.add(beginDay + "下午");
                } else {
                    times.add(beginDay);
                }
            } else {
                beginDay = "0".equals(beginHour) ? beginDay : beginDay + "下午";
                endDay = "12".equals(endHour) ? endDay + "上午" : endDay;
                times.add(beginDay + "~" + endDay);
            }
        }
        Collections.reverse(times);
        return StringUtils.join(times, "、");
    }

    private List<TAttendance> getStandardTime(List<TAttendance> attendances, SearchAttendanceCondition condition) {
        List<TAttendance> list = new ArrayList<TAttendance>();
        for (TAttendance attendance : attendances) {
            if (attendance.getEndTime() == null) {
                if (StringUtils.isNotBlank(attendance.getApm())) {
                    Date now = new Date();
                    if (now.compareTo(DateUtils.getStartOfDay(attendance.getBeginTime())) >= 0) {
                        attendance.setEndTime(DateUtils.setHours(DateUtils.getStartOfDay(now), 18));
                    } else {
                        continue;
                    }
                    correctTime(attendance, condition);
                } else {
                    continue;
                }
            }
            String beginHour = DateUtils.formatDate(attendance.getBeginTime(), "H");
            String endHour = DateUtils.formatDate(attendance.getEndTime(), "H");
            if (StringUtils.isNotBlank(attendance.getApm())) {
                if ("8".equals(beginHour)) {
                    attendance.setBeginTime(DateUtils.getStartOfDay(attendance.getBeginTime()));
                }
                if ("14".equals(beginHour)) {
                    attendance.setBeginTime(DateUtils.setHours(attendance.getBeginTime(), 12));
                }
                if ("18".equals(endHour)) {
                    attendance.setEndTime(DateUtils.getEndOfDay(attendance.getEndTime()));
                }
            } else {
                if (Integer.parseInt(endHour) <= 12) {
                    attendance.setBeginTime(DateUtils.getStartOfDay(attendance.getBeginTime()));
                    attendance.setEndTime(DateUtils.setHours(DateUtils.getStartOfDay(attendance.getEndTime()), 12));
                } else if (Integer.parseInt(beginHour) >= 12) {
                    attendance.setBeginTime(DateUtils.setHours(DateUtils.getStartOfDay(attendance.getBeginTime()), 12));
                    attendance.setEndTime(DateUtils.getEndOfDay(attendance.getEndTime()));
                } else {
                    attendance.setBeginTime(DateUtils.getStartOfDay(attendance.getBeginTime()));
                    attendance.setEndTime(DateUtils.getEndOfDay(attendance.getEndTime()));
                }
            }
            list.add(attendance);
        }
        return list;
    }

    private List<TAttendance> mergeDate(List<TAttendance> attendances) {
        Collections.sort(attendances, new Comparator<TAttendance>() {

            public int compare(TAttendance o1, TAttendance o2) {
                return o1.getBeginTime().compareTo(o2.getBeginTime());
            }
        });
        Stack<Long> s = new Stack<Long>();
        Stack<Long> e = new Stack<Long>();
        s.push(0L);
        e.push(0L);
        for (TAttendance attendance : attendances) {
            if (attendance.getBeginTime().getTime() > e.peek()) {
                s.push(attendance.getBeginTime().getTime());
                e.push(attendance.getEndTime().getTime());
            } else if (attendance.getEndTime().getTime() >= e.peek()) {
                e.pop();
                e.push(attendance.getEndTime().getTime());
            } else if (attendance.getBeginTime().getTime() <= s.peek()) {
                s.pop();
                s.push(attendance.getBeginTime().getTime());
            }
        }
        List<TAttendance> list = new ArrayList<TAttendance>();
        while (!s.isEmpty()) {
            if (0 != s.peek() && 0 != e.peek() && (0 != (int) (e.peek() - s.peek()))) {
                TAttendance attendance = new TAttendance();
                attendance.setBeginTime(new Date(s.peek()));
                attendance.setEndTime(new Date(e.peek()));
                list.add(attendance);
            }
            s.pop();
            e.pop();
        }
        return list;
    }

    public Date getEndDayOfYear(Date time) {
        Calendar cal = Calendar.getInstance();
        if (time != null) {
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_YEAR, cal.getActualMaximum(Calendar.DAY_OF_YEAR));
        cal.set(Calendar.HOUR_OF_DAY, cal.getActualMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
        return cal.getTime();
    }

    public Date getEndDayOfMonth(Date time) {
        Calendar cal = Calendar.getInstance();
        if (time != null) {
            cal.setTime(time);
        }
        cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
        cal.set(Calendar.HOUR_OF_DAY, cal.getActualMaximum(Calendar.HOUR_OF_DAY));
        cal.set(Calendar.MINUTE, cal.getActualMaximum(Calendar.MINUTE));
        cal.set(Calendar.SECOND, cal.getActualMaximum(Calendar.SECOND));
        return cal.getTime();
    }

//    public double countDays(List<TAttendance> attendances, SearchAttendanceCondition condition){
//        if (attendances.size() == 0){
//            return 0;
//        }
//        double countDays = 0;
//        for (TAttendance attendance : attendances) {
//            correctTime(attendance, condition);
//            long ms = attendance.getEndTime().getTime() - attendance.getBeginTime().getTime();
//            double days = (double)ms/(24*60*60*1000);
//            TDirectory h2d = directoryService.findDirectories("HOUR_DAY_CONFIG").get(0);
//            if (h2d != null){
//                double mark = Double.valueOf(h2d.getDirValue());
//                double overDays = days - (int)days;
//                overDays = overDays*24<=mark ? 0.5 : 1;
//                days = (int)days + overDays;
//            }else {
//                days = (double)Math.round(days*10)/10;
//            }
//            countDays += days;
//        }
//        return countDays;
//    }

//    public double countDays(List<TAttendance> attendances, SearchAttendanceCondition condition){
//        if (attendances.size() == 0){
//            return 0;
//        }
//        long ms = 0;
//        for (TAttendance attendance : attendances) {
//            correctTime(attendance, condition);
//            ms += attendance.getEndTime().getTime() - attendance.getBeginTime().getTime();
//        }
//        double days = (double)ms/(24*60*60*1000);
//        TDirectory h2d = directoryService.findDirectories("HOUR_DAY_CONFIG").get(0);
//        if (h2d != null){
//            double mark = Double.valueOf(h2d.getDirValue());
//            double overDays = days - (int)days;
//            overDays = overDays*24<=mark ? 0.5 : 1;
//            days = (int)days + overDays;
//        }else {
//            days = (double)Math.round(days*10)/10;
//        }
//        return days;
//    }

}
